package entities;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import util.ConfigurationParser;

public class RoutingTable {

	private Map<Integer, Map<Integer, Integer>> distanceMap;

	public RoutingTable() {
		distanceMap = new HashMap<Integer, Map<Integer, Integer>>();
	}

	public RoutingTable(Map<Integer, Map<Integer, Integer>> map) {
		distanceMap = map;
	}

	public void put(int routerId, int nextHopId, int weight) {
		if (distanceMap.get(routerId) == null) {
			distanceMap.put(routerId, new HashMap<Integer, Integer>());
			distanceMap.get(routerId).put(nextHopId, weight);
		} else {
			distanceMap.get(routerId).put(nextHopId, weight);
		}
	}
	
	public Map<Integer, Integer> getDistanceVector(int id) {
		return distanceMap.get(id);
	}

	public int getDistance(int xId, int yId) {
		try {
			return distanceMap.get(xId).get(yId);	
		} catch (NullPointerException e) {
			return Router.INFINITY;
		}
		
	}
	
	public void update(int routerId, Map<Integer, Integer> distMap) {
		distanceMap.put(routerId, distMap);
	}

	/**
	 * Retorna a tabela de distancias para um determinado roteador codificada em
	 * um array de bytes.
	 * 
	 * @param routerId
	 *            o id do roteador
	 * @return o array de bytes
	 */
	public byte[] getTable(int routerId) {
		String table = new String();
		for (Entry<Integer, Integer> entry : distanceMap.get(routerId)
				.entrySet()) {
			table += entry.getKey() + "-" + entry.getValue() + ";";
		}

		return table.getBytes();
	}

	public static Map<Integer, Integer> parseTable(String table) {
		Map<Integer, Integer> distMap = new HashMap<Integer, Integer>();
		String[] lines = table.split(";");
		for (String line : lines) {
			// System.out.println("Debug: " + line);
			String[] entry = line.split("-");
			int nextHop = Integer.parseInt(entry[0]);
			int weight = Integer.parseInt(entry[1]);

			distMap.put(nextHop, weight);
		}
		return distMap;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		String table = "|     | ";
		for (Integer key : distanceMap.keySet()) {
			table += formatNumber(key) + " | ";
		}
		table = table.trim() + System.getProperty("line.separator");

		for (Integer key : distanceMap.keySet()) {
			table += "| " + formatNumber(key) + " | ";
			for (Integer key2 : distanceMap.keySet()) {
				table += (distanceMap.get(key).containsKey(key2)) ? formatNumber(distanceMap
						.get(key).get(key2))
						+ " | "
						: "0   | ";
			}
			table += System.getProperty("line.separator");
		}

		return table;
	}

	public String toString(int id) {
		String table = "|   | ";
		for (Integer rId : ConfigurationParser.getInstance().getRouters()
				.keySet()) {
			table += formatNumber(rId) + " | ";
		}
		table = table.trim() + System.getProperty("line.separator") + "| " + id
				+ " | ";
		for (Integer entry : ConfigurationParser.getInstance().getRouters()
				.keySet()) {
			table += (distanceMap.get(id).containsKey(entry)) ? formatNumber(distanceMap
					.get(id).get(entry))
					+ " | "
					: "0   | ";
		}
		return table;
	}

	public void printDistancemap() {
		System.out.println(distanceMap);
	}

	private String formatNumber(int i) {
		String number = Integer.toString(i);
		int len = number.length();
		switch (len) {
		case 1:
			number += "  ";
			break;
		case 2:
			number += " ";
			break;
		case 3:
			number = (i == 999) ? "INF" : number;
		default:
			break;
		}
		return number;
	}
}
